﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using VBAConvertor.Parsers;

namespace VBAConvertor
{
    class ConvertEngine
    {
        private readonly List<ILineParser> _LineParsers;
        private readonly List<ILineParser> _PartsParsers;
        private readonly List<ILineParser> _PrePartsParser; 

        public ConvertEngine(bool autoDocParam)
        {
            _PrePartsParser = new List<ILineParser>
                {
                    new StrAddReplaceParser(),
                };
            _LineParsers = new List<ILineParser>
                {
                    new DimParser(),
                    new IfParser(),
                    new ElseParser(),
                    new ElseIfParser(),
                    new EndIfParser(),
                    new WithParser(),
                    new EndWithParser(),
                    new SubParser(autoDocParam),
                    new EndSubParser(),
                    new FuncParser(autoDocParam),
                    new EndFuncParser(),
                    new ForParser(),
                    new ForEachParser(),
                    new EndForParser(),
                    new ExitParser(),
                };
            _PartsParsers = new List<ILineParser>
                {
                    new WordReplacementParser(),
                    new InWithParser(),
                    new OpReplacementParser(),
                    new MeReplacementParser(),
                    new EnumReplacementParser(),
                    new IndexPropertyReplacementParser(),
                    new AppPrefixParser(),
                };
        }

        public string Parse(LinesReader input)
        {
            var cSharCodes = new StringBuilder();
            var statuses = new Stack<ParseStatus>();
            statuses.Push(new ParseStatus {CurrentState = State.ClassDef});

            while (true)
            {
                var comments = new StringBuilder();
                var lineContent = ReadNextNotEmptyLine(input, comments);
                if (string.IsNullOrEmpty(lineContent))
                {
                    break;
                }

                var cSharpLine = lineContent;

                var lineClosed = false;
                foreach (var lineParser in _PrePartsParser)
                {
                    bool success;
                    cSharpLine = lineParser.Parse(statuses, cSharpLine, input, out success, ref lineClosed);
                }
                
                foreach (var lineParser in _LineParsers)
                {
                    bool success;
                    cSharpLine = lineParser.Parse(statuses, cSharpLine, input, out success, ref lineClosed);
                    if (success)
                    {
                        break;
                    }
                }

                foreach (var lineParser in _PartsParsers)
                {
                    bool success;
                    cSharpLine = lineParser.Parse(statuses, cSharpLine, input, out success, ref lineClosed);
                }

                if (comments.Length > 0)
                {
                    cSharCodes.AppendLine(comments.ToString());
                }
                
                cSharCodes.Append(cSharpLine);
                if (!lineClosed)
                {
                    cSharCodes.Append(";");
                }
                cSharCodes.AppendLine();
            }

            return cSharCodes.ToString();
        }

        public static string ReadNextNotEmptyLine(LinesReader input, StringBuilder comments)
        {
            string lineContent = null;
            while ((string.IsNullOrEmpty(lineContent) || string.IsNullOrEmpty(lineContent = lineContent.Trim())) && !input.End)
            {
                lineContent = input.ReadLine();
            }
            if (string.IsNullOrEmpty(lineContent))
            {
                return lineContent;
            }
            
            var commentIndex = lineContent.IndexOf('\'');
            if (commentIndex >= 0)
            {
                comments.Append("//");
                comments.AppendLine(lineContent.Substring(commentIndex));
                lineContent = lineContent.Substring(0, commentIndex).Trim();
                if (string.IsNullOrEmpty(lineContent))
                {
                    lineContent = ReadNextNotEmptyLine(input, comments);
                }
            }

            if (lineContent.EndsWith("_"))
            {
                lineContent = lineContent.Substring(0, lineContent.Length - 1).Trim() + " " + ReadNextNotEmptyLine(input, comments).Trim();
            }

            return lineContent;
        }
    }
}
